// START: header
tree grammar ModelRef;
options {
  tokenVocab = Model;
  ASTLabelType = ModelAST;
  filter = true;
}

@header {package samples;}

/** topdown because we want to reference symbols in order. Don't need
 *  bottomup pattern matching; we're not computing current scope.
 */
topdown
    :   enterMethod
    |   enterClass
    |	enterInterface
    |   fieldDeclaration
    ;

enterInterface
    :   ^('interface' name=IDENTIFIER (^('extends' sup=IDENTIFIER))? .)
        {
        if ( $sup!=null ) {
            // look up superclass (if any)
            $sup.symbol = $sup.scope.resolve($sup.text);
            ((ClassSymbol)$name.symbol).superClass =
                (ClassSymbol)$sup.symbol;                // set superclass
            System.out.println("line "+$name.getLine()+": set "+$name.text+
                " super to "+((ClassSymbol)$name.symbol).superClass);
        }
        else {
            System.out.println("line "+$name.getLine()+": set "+$name.symbol);
        }
        }
    ;

enterClass
    :   ^('class' name=IDENTIFIER (^('implements' sup=IDENTIFIER))? .)
        {
        if ( $sup!=null ) {
            // look up superclass (if any)
            $sup.symbol = $sup.scope.resolve($sup.text);
            ((ClassSymbol)$name.symbol).superClass =
                (ClassSymbol)$sup.symbol;                // set superclass
            System.out.println("line "+$name.getLine()+": set "+$name.text+
                " super to "+((ClassSymbol)$name.symbol).superClass);
        }
        else {
            System.out.println("line "+$name.getLine()+": set "+$name.symbol);
        }
        }
    ;

enterMethod
    :   ^(METHOD_DECL type ID=IDENTIFIER)
        {
        $ID.symbol.type = (Type) $type.tsym; // set return type of method
        System.out.println("line "+$ID.getLine()+": set method type "+$type.tsym);
        }
    ;


fieldDeclaration // global, parameter, or local variable
    :   ^(FIELD_DECL  type ID=IDENTIFIER)
        {
        $ID.symbol.type = (Type) $type.tsym; // set return type of variable
        System.out.println("line "+$ID.getLine()+": set VarType "+$ID.symbol);
        }
    ;

type returns [Type tsym]
    :   ^((REL_DECL|TYPE_DECL) ID=IDENTIFIER)
		{
	    // get scope from AST; use to resolve type name and save it in AST
	    $ID.symbol = $ID.scope.resolve($ID.text);
	    $tsym = (Type)$ID.symbol; // return Type from this rule
		}
    ;

